﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AFCEPF.BankApplication.BLL
{
    /// <summary>
    /// Abstract base class for all account types.
    /// </summary>
    public abstract class AccountBase : IVisitable
    {
        private double _balance;
        private Customer _holder;


        /// <summary>
        /// Occurs when a withdrawal is performed over a negative balance.
        /// </summary>
        public event EventHandler<AccountEventArgs> NegativeBalanceWithdraw;


        /// <summary>
        /// Occurs when a withdrawal is performed on an account
        /// exceeding its overdraw limit.
        /// </summary>
        public event EventHandler<AccountEventArgs> OverLimitWithdraw;


        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="holder">The Account holder.</param>
        /// <param name="initialDeposit">The initial deposit.</param>
        protected AccountBase(Customer holder, double initialDeposit)
        {
            _holder = holder;

            Deposit(initialDeposit);
        }




        /// <summary>
        /// Gets the balance.
        /// </summary>
        public double Balance
        {
            get             { return _balance;  }
            internal set    { _balance = value; }
        }

        /// <summary>
        /// Gets the holder.
        /// </summary>
        public Customer Holder
        {
            get { return _holder; }
        }

        /// <summary>
        /// Returns true if the current account's balance 
        /// is under the authorized overdrawn amount, else false.
        /// </summary>
        public bool IsAccountExcessOverdrawn
        {
            get { return _balance < -GetOverdrawnAmount(); }
        }


        /// <summary>
        /// Deposits the specified amount.
        /// </summary>
        /// <param name="amount">The amount.</param>
        public void Deposit(double amount)
        {
            if (amount > 0)
            {
                _balance += amount;
            }
        }

        /// <summary>
        /// Withdraws the specified amount.
        /// </summary>
        /// <param name="amount">The amount.</param>        
        public void Withdraw(double amount)
        {
            if (amount > 0)
            {
                _balance -= amount;
            }

            // Fire the two events as needed.
            OnNegativeBalanceWithdraw();
            OnOverLimitWithdraw();
        }
            

        /// <summary>
        /// Raises the NegativeBalanceWithdraw event if needed.
        /// </summary>
        protected virtual void OnNegativeBalanceWithdraw()
        {
            if (_balance < 0)
            {
                // Let's check if there are methods that subscribed 
                // to the event before firing it.
                if (NegativeBalanceWithdraw != null)
	            {
                    // Fire event.
		            NegativeBalanceWithdraw(this, new AccountEventArgs(_holder, Balance));
                }
            }
        }


        /// <summary>
        /// Raises the NegativeBalanceWithdraw event if needed.
        /// </summary>
        protected virtual void OnOverLimitWithdraw()
        {
            if (_balance < -GetOverdrawnAmount())
            {
                // Let's check if there are methods that subscribed 
                // to the event before firing it.
                if (OverLimitWithdraw != null)
                {
                    // Fire event.
                    OverLimitWithdraw(this, new AccountEventArgs(_holder, Balance));
                }
            }
        }


        /// <summary>
        /// Gets the authorized overdrawn amount for the current 
        /// account type.
        /// This method will be overriden in derived classes.
        /// </summary>
        /// <returns>the authorized overdrawn amount</returns>        
        public abstract double GetOverdrawnAmount();





        #region -- IVisitable Members --

        /// <summary>
        /// Accepts the specified visitor.
        /// </summary>
        /// <param name="visitor">The visitor.</param>
        public void Accept(IVisitor visitor)
        {
            // Tells the IVisitor implementor
            // to perform operations on 
            // the current instance..
            visitor.Visit(this);
        }

        #endregion
    }
}
